﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion

namespace MetaHeuristics.Aco
{
    using MetaHeuristics.Collections;
    public class AsPheromoneUpdater : BasePheromoneUpdater
    {
        private SymmetricFloatMatrix heuristicInformations = null;
        private double damping= 0.5f;
        private double pheromoneExponent = 1;
        private double heuristicExponent = 2;

        public double Damping
        {
            get
            {
                return this.damping;
            }
            set
            {
                this.damping = Math.Max(0, Math.Min(1, value));
            }
        }

        public double PheromoneExponent
        {
            get
            {
                return this.pheromoneExponent;
            }
            set
            {
                this.pheromoneExponent = value;
            }
        }

        public double HeuristicExponent
        {
            get
            {
                return this.heuristicExponent;
            }
            set
            {
                this.heuristicExponent = value;
            }
        }

        public override void Initialize()
        {
            this.heuristicInformations = new SymmetricFloatMatrix(this.Aco.Cities.Count, 0);
            for (int i = 0; i < this.Aco.Cities.Count; ++i)
            {
                for (int j = i + 1; j < this.Aco.Cities.Count; ++j)
                {
                    double invDistance= checked(1/this.Aco.Distances[i,j] );
                    this.heuristicInformations[i, j] = (float)Math.Pow(invDistance, this.heuristicExponent);
                }
            }
        }

        public override void Update()
        {
            this.Evaporate();
            foreach (Ant ant in this.Aco.Ants)
            {
                this.DepositPheromone(ant);
            }
            this.ComputeChoiceInformation();
        }

        protected virtual void Evaporate()
        {
            float oneMinusDamping = (float)(1-this.damping);
            for (int i = 0; i < this.Aco.Cities.Count; ++i)
            {
                for (int j = i; j < this.Aco.Cities.Count; ++j)
                {
                    float pheromone = oneMinusDamping * this.Aco.Pheromones[i, j];
                    this.Aco.Pheromones[i, j] = pheromone;
                }
            }
        }

        protected virtual void DepositPheromone(Ant ant)
        {
            float deltaTau = (float)checked(1.0 / ant.Tours.Length);

            for (int i = 0; i < this.Aco.Cities.Count; ++i)
            {
                int j = ant.Tours[i];
                int l = ant.Tours[i + 1];

                this.Aco.Pheromones[j, l] += deltaTau;
            }
        }

        protected virtual void ComputeChoiceInformation()
        {
            for (int i = 0; i < this.Aco.Cities.Count; ++i)
            {
                for (int j = i + 1; j < this.Aco.Cities.Count; ++j)
                {
                    float pheromone = this.Aco.Pheromones[i,j];
                    double pheromoneInfo = Math.Pow(pheromone, this.pheromoneExponent);
                    double choiceInfo = pheromoneInfo * this.heuristicInformations[i, j];
                    this.Aco.ChoiceInfos[i, j] = (float)choiceInfo;
                }
            }
        }
    }
}
